package org.ym.thread.application;

import com.google.common.base.Preconditions;
import org.ym.basic.FileSnowflakeIdWorker;
import org.ym.thread.application.command.ThreadPoolCreateCommand;
import org.ym.thread.application.command.ThreadPoolExecuteCommand;
import org.ym.thread.application.command.ThreadPoolUpdateCommand;
import org.ym.thread.application.model.ResizableCapacityLinkedBlockingQueue;
import org.ym.thread.application.results.ThreadPoolInfo;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.concurrent.*;

/**
 * @author ym
 */
public class ThreadCenterDispatch {
    /**
     * 实例
     */
    private static ThreadCenterDispatch instance;
    /**
     * 线程池仓库
     */
    private static final ConcurrentMap<Long, ThreadPoolExecutor> THREAD_POOL_CENTER = new ConcurrentHashMap<>();

    private ThreadCenterDispatch() {
    }

    /**
     * 获取实例
     *
     * @return ThreadCenterDispatch
     */
    public static ThreadCenterDispatch getInstance() {
        if (instance == null) {
            synchronized (ThreadCenterDispatch.class) {
                if (instance == null) {
                    instance = new ThreadCenterDispatch();
                }
            }
        }
        return instance;
    }

    /**
     * 创建线程池
     *
     * @param threadPoolCreateCommand 线程池创建命令
     * @return 线程池信息
     */
    public ThreadPoolInfo create(ThreadPoolCreateCommand threadPoolCreateCommand) {
        Preconditions.checkNotNull(threadPoolCreateCommand, "threadPoolCreateCommand can not be null");
        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(
                threadPoolCreateCommand.getCorePoolSize()
                , threadPoolCreateCommand.getMaximumPoolSize()
                , threadPoolCreateCommand.getKeepAliveTime()
                , TimeUnit.MILLISECONDS
                , new ResizableCapacityLinkedBlockingQueue<>(threadPoolCreateCommand.getQueueSize())
                , Executors.defaultThreadFactory()
                , new ThreadPoolExecutor.AbortPolicy()
        );
        threadPoolExecutor.allowCoreThreadTimeOut(true);
        long key = FileSnowflakeIdWorker.genIdByLong();
        THREAD_POOL_CENTER.put(key, threadPoolExecutor);
        return ThreadPoolInfo.of(key,threadPoolExecutor);
    }
    /**
     * 更新线程池
     *
     * @param threadPoolUpdateCommand 更新命令
     * @return
     */
    public ThreadPoolInfo update(ThreadPoolUpdateCommand threadPoolUpdateCommand) {
        if (threadPoolUpdateCommand != null) {
            ThreadPoolExecutor threadPoolExecutor = THREAD_POOL_CENTER.get(threadPoolUpdateCommand.getKey());
            if (threadPoolExecutor != null) {
                if (threadPoolUpdateCommand.getCorePoolSize() != null) {
                    threadPoolExecutor.setCorePoolSize(threadPoolUpdateCommand.getCorePoolSize());
                }
                if (threadPoolUpdateCommand.getMaximumPoolSize() != null) {
                    threadPoolExecutor.setMaximumPoolSize(threadPoolUpdateCommand.getMaximumPoolSize());
                }
                if (threadPoolUpdateCommand.getQueueSize() != null) {
                    ResizableCapacityLinkedBlockingQueue resizableCapacityLinkedBlockingQueue = (ResizableCapacityLinkedBlockingQueue) threadPoolExecutor.getQueue();
                    resizableCapacityLinkedBlockingQueue.setCapacity(threadPoolUpdateCommand.getQueueSize());
                }
            }
            return ThreadPoolInfo.of(threadPoolUpdateCommand.getKey(),threadPoolExecutor);
        }
        return null;
    }

    /**
     * 执行线程任务
     * @param threadPoolExecuteCommand 执行命令
     */
    public void execute(ThreadPoolExecuteCommand threadPoolExecuteCommand) {
        if (threadPoolExecuteCommand != null) {
            ThreadPoolExecutor threadPoolExecutor = THREAD_POOL_CENTER.get(threadPoolExecuteCommand.getKey());
            if(threadPoolExecutor != null){
                threadPoolExecutor.execute(threadPoolExecuteCommand.getRunnable());
            }
        }
    }

    /**
     * 当前线程池信息
     * @return 信息集合
     */
    public List<ThreadPoolInfo> queryAll(){
        List<ThreadPoolInfo> list = new ArrayList<>();
        Iterator<Map.Entry<Long,ThreadPoolExecutor>> iterator = THREAD_POOL_CENTER.entrySet().iterator();
        Map.Entry<Long,ThreadPoolExecutor> entry;
        while (iterator.hasNext()){
            entry = iterator.next();
            list.add(ThreadPoolInfo.of(entry.getKey(),entry.getValue()));
        }
        return list;
    }

    /**
     * 获取单条
     * @param key key
     * @return 信息
     */
    public ThreadPoolInfo get(Long key){
        return ThreadPoolInfo.of(key,THREAD_POOL_CENTER.get(key));
    }
}
